import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

public class DESTool extends JFrame {
    private JTextArea inputTextArea;
    private JTextArea outputTextArea;
    private JTextField keyField1, keyField2, keyField3;
    private JButton encryptButton, decryptButton;
    private JButton tripleEncryptButton, tripleDecryptButton;
    private JComboBox<String> modeComboBox;

    // DES置换表
    private static final int[] IP = {
            58, 50, 42, 34, 26, 18, 10, 2,
            60, 52, 44, 36, 28, 20, 12, 4,
            62, 54, 46, 38, 30, 22, 14, 6,
            64, 56, 48, 40, 32, 24, 16, 8,
            57, 49, 41, 33, 25, 17, 9, 1,
            59, 51, 43, 35, 27, 19, 11, 3,
            61, 53, 45, 37, 29, 21, 13, 5,
            63, 55, 47, 39, 31, 23, 15, 7
    };

    private static final int[] FP = {
            40, 8, 48, 16, 56, 24, 64, 32,
            39, 7, 47, 15, 55, 23, 63, 31,
            38, 6, 46, 14, 54, 22, 62, 30,
            37, 5, 45, 13, 53, 21, 61, 29,
            36, 4, 44, 12, 52, 20, 60, 28,
            35, 3, 43, 11, 51, 19, 59, 27,
            34, 2, 42, 10, 50, 18, 58, 26,
            33, 1, 41, 9, 49, 17, 57, 25
    };

    // PC-1置换表
    private static final int[] PC1 = {
            57, 49, 41, 33, 25, 17, 9,
            1, 58, 50, 42, 34, 26, 18,
            10, 2, 59, 51, 43, 35, 27,
            19, 11, 3, 60, 52, 44, 36,
            63, 55, 47, 39, 31, 23, 15,
            7, 62, 54, 46, 38, 30, 22,
            14, 6, 61, 53, 45, 37, 29,
            21, 13, 5, 28, 20, 12, 4
    };

    // PC-2置换表
    private static final int[] PC2 = {
            14, 17, 11, 24, 1, 5,
            3, 28, 15, 6, 21, 10,
            23, 19, 12, 4, 26, 8,
            16, 7, 27, 20, 13, 2,
            41, 52, 31, 37, 47, 55,
            30, 40, 51, 45, 33, 48,
            44, 49, 39, 56, 34, 53,
            46, 42, 50, 36, 29, 32
    };

    // 左移位数表
    private static final int[] SHIFTS = {
            1, 1, 2, 2, 2, 2, 2, 2,
            1, 2, 2, 2, 2, 2, 2, 1
    };

    public DESTool() {
        initializeUI();
    }

    private void initializeUI() {
        setTitle("DES加密工具");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 输入区域
        JPanel inputPanel = new JPanel(new BorderLayout());
        inputPanel.setBorder(BorderFactory.createTitledBorder("输入文本"));
        inputTextArea = new JTextArea(5, 40);
        inputPanel.add(new JScrollPane(inputTextArea), BorderLayout.CENTER);

        // 输出区域
        JPanel outputPanel = new JPanel(new BorderLayout());
        outputPanel.setBorder(BorderFactory.createTitledBorder("输出文本"));
        outputTextArea = new JTextArea(5, 40);
        outputTextArea.setEditable(false);
        outputPanel.add(new JScrollPane(outputTextArea), BorderLayout.CENTER);

        // 密钥区域
        JPanel keyPanel = new JPanel(new GridLayout(4, 2, 5, 5));
        keyPanel.setBorder(BorderFactory.createTitledBorder("密钥设置"));

        keyPanel.add(new JLabel("DES密钥 (8字符):"));
        keyField1 = new JTextField("12345678");
        keyPanel.add(keyField1);

        keyPanel.add(new JLabel("3DES密钥2 (8字符):"));
        keyField2 = new JTextField("key12345");
        keyPanel.add(keyField2);

        keyPanel.add(new JLabel("3DES密钥3 (8字符):"));
        keyField3 = new JTextField("key67890");
        keyPanel.add(keyField3);

        keyPanel.add(new JLabel("模式:"));
        modeComboBox = new JComboBox<>(new String[]{"DES", "3DES"});
        keyPanel.add(modeComboBox);

        // 按钮区域
        JPanel buttonPanel = new JPanel(new FlowLayout());
        encryptButton = new JButton("DES加密");
        decryptButton = new JButton("DES解密");
        tripleEncryptButton = new JButton("3DES加密");
        tripleDecryptButton = new JButton("3DES解密");

        buttonPanel.add(encryptButton);
        buttonPanel.add(decryptButton);
        buttonPanel.add(tripleEncryptButton);
        buttonPanel.add(tripleDecryptButton);

        // 添加组件到主窗口
        JPanel centerPanel = new JPanel(new GridLayout(3, 1, 10, 10));
        centerPanel.add(inputPanel);
        centerPanel.add(keyPanel);
        centerPanel.add(outputPanel);

        add(centerPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);

        addEventListeners();

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void addEventListeners() {
        encryptButton.addActionListener(e -> {
            try {
                String input = inputTextArea.getText().trim();
                if (input.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "请输入要加密的文本!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String key = keyField1.getText().trim();
                if (key.length() != 8) {
                    JOptionPane.showMessageDialog(this, "DES密钥必须为8个字符!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String encrypted = encryptString(input, key);
                outputTextArea.setText(encrypted);
                JOptionPane.showMessageDialog(this, "DES加密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "DES加密错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        });

        decryptButton.addActionListener(e -> {
            try {
                String input = inputTextArea.getText().trim();
                if (input.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "请输入要解密的密文!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String key = keyField1.getText().trim();
                if (key.length() != 8) {
                    JOptionPane.showMessageDialog(this, "DES密钥必须为8个字符!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // 检查输入是否是有效的十六进制
                if (!isValidHex(input)) {
                    JOptionPane.showMessageDialog(this,
                            "请输入有效的十六进制密文!\n密文应该只包含0-9, a-f, A-F字符",
                            "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                String decrypted = decryptString(input, key);
                outputTextArea.setText(decrypted);
                JOptionPane.showMessageDialog(this, "DES解密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "DES解密错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        });

        tripleEncryptButton.addActionListener(e -> {
            try {
                String input = inputTextArea.getText().trim();
                if (input.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "请输入要加密的文本!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String key1 = keyField1.getText().trim();
                String key2 = keyField2.getText().trim();
                String key3 = keyField3.getText().trim();
                if (key1.length() != 8 || key2.length() != 8 || key3.length() != 8) {
                    JOptionPane.showMessageDialog(this, "所有3DES密钥必须为8个字符!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String encrypted = tripleEncryptString(input, key1, key2, key3);
                outputTextArea.setText(encrypted);
                JOptionPane.showMessageDialog(this, "3DES加密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "3DES加密错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        });

        tripleDecryptButton.addActionListener(e -> {
            try {
                String input = inputTextArea.getText().trim();
                if (input.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "请输入要解密的密文!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                String key1 = keyField1.getText().trim();
                String key2 = keyField2.getText().trim();
                String key3 = keyField3.getText().trim();
                if (key1.length() != 8 || key2.length() != 8 || key3.length() != 8) {
                    JOptionPane.showMessageDialog(this, "所有3DES密钥必须为8个字符!", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // 检查输入是否是有效的十六进制
                if (!isValidHex(input)) {
                    JOptionPane.showMessageDialog(this,
                            "请输入有效的十六进制密文!\n密文应该只包含0-9, a-f, A-F字符",
                            "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                String decrypted = tripleDecryptString(input, key1, key2, key3);
                outputTextArea.setText(decrypted);
                JOptionPane.showMessageDialog(this, "3DES解密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "3DES解密错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        });
    }

    // 检查字符串是否为有效的十六进制
    private boolean isValidHex(String text) {
        if (text == null || text.isEmpty()) return false;
        for (char c : text.toCharArray()) {
            if (!Character.isDigit(c) && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) {
                return false;
            }
        }
        return text.length() % 2 == 0; // 十六进制长度应为偶数
    }

    // 字符串加密方法
    public String encryptString(String plaintext, String key) {
        try {
            byte[] plaintextBytes = plaintext.getBytes("UTF-8");
            byte[] keyBytes = key.getBytes("UTF-8");
            byte[] encryptedBytes = encrypt(plaintextBytes, keyBytes);
            return bytesToHex(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("加密字符串时出错: " + e.getMessage(), e);
        }
    }

    // 字符串解密方法
    public String decryptString(String ciphertext, String key) {
        try {
            byte[] ciphertextBytes = hexToBytes(ciphertext);
            byte[] keyBytes = key.getBytes("UTF-8");
            byte[] decryptedBytes = decrypt(ciphertextBytes, keyBytes);
            return new String(decryptedBytes, "UTF-8").trim();
        } catch (Exception e) {
            throw new RuntimeException("解密字符串时出错: " + e.getMessage(), e);
        }
    }

    // 三重加密字符串方法
    public String tripleEncryptString(String plaintext, String key1, String key2, String key3) {
        try {
            byte[] plaintextBytes = plaintext.getBytes("UTF-8");
            byte[] key1Bytes = key1.getBytes("UTF-8");
            byte[] key2Bytes = key2.getBytes("UTF-8");
            byte[] key3Bytes = key3.getBytes("UTF-8");
            byte[] encryptedBytes = tripleEncrypt(plaintextBytes, key1Bytes, key2Bytes, key3Bytes);
            return bytesToHex(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("三重加密字符串时出错: " + e.getMessage(), e);
        }
    }

    // 三重解密字符串方法
    public String tripleDecryptString(String ciphertext, String key1, String key2, String key3) {
        try {
            byte[] ciphertextBytes = hexToBytes(ciphertext);
            byte[] key1Bytes = key1.getBytes("UTF-8");
            byte[] key2Bytes = key2.getBytes("UTF-8");
            byte[] key3Bytes = key3.getBytes("UTF-8");
            byte[] decryptedBytes = tripleDecrypt(ciphertextBytes, key1Bytes, key2Bytes, key3Bytes);
            return new String(decryptedBytes, "UTF-8").trim();
        } catch (Exception e) {
            throw new RuntimeException("三重解密字符串时出错: " + e.getMessage(), e);
        }
    }

    // 主要的DES加密方法
    public byte[] encrypt(byte[] data, byte[] key) {
        // 确保数据是8字节的倍数
        int length = data.length;
        int paddedLength = ((length + 7) / 8) * 8;
        byte[] paddedData = new byte[paddedLength];
        System.arraycopy(data, 0, paddedData, 0, length);

        // 设置PKCS5填充
        byte padValue = (byte) (paddedLength - length);
        for (int i = length; i < paddedLength; i++) {
            paddedData[i] = padValue;
        }

        byte[] result = new byte[paddedLength];

        // 对每个8字节块进行加密
        for (int i = 0; i < paddedLength; i += 8) {
            byte[] block = new byte[8];
            System.arraycopy(paddedData, i, block, 0, 8);
            byte[] encryptedBlock = encryptBlock(block, key);
            System.arraycopy(encryptedBlock, 0, result, i, 8);
        }

        return result;
    }

    // 主要的DES解密方法
    public byte[] decrypt(byte[] data, byte[] key) {
        if (data.length % 8 != 0) {
            throw new IllegalArgumentException("数据长度必须是8的倍数，当前长度: " + data.length);
        }

        byte[] result = new byte[data.length];

        // 对每个8字节块进行解密
        for (int i = 0; i < data.length; i += 8) {
            byte[] block = new byte[8];
            System.arraycopy(data, i, block, 0, 8);
            byte[] decryptedBlock = decryptBlock(block, key);
            System.arraycopy(decryptedBlock, 0, result, i, 8);
        }

        // 移除PKCS5填充
        int padValue = result[result.length - 1] & 0xFF;
        if (padValue > 0 && padValue <= 8) {
            // 验证填充
            boolean validPadding = true;
            for (int i = result.length - padValue; i < result.length; i++) {
                if ((result[i] & 0xFF) != padValue) {
                    validPadding = false;
                    break;
                }
            }
            if (validPadding) {
                byte[] finalResult = new byte[result.length - padValue];
                System.arraycopy(result, 0, finalResult, 0, finalResult.length);
                return finalResult;
            }
        }

        return result;
    }

    // 三重DES加密
    public byte[] tripleEncrypt(byte[] data, byte[] key1, byte[] key2, byte[] key3) {
        byte[] step1 = encrypt(data, key1);
        byte[] step2 = decrypt(step1, key2);
        return encrypt(step2, key3);
    }

    // 三重DES解密
    public byte[] tripleDecrypt(byte[] data, byte[] key1, byte[] key2, byte[] key3) {
        byte[] step1 = decrypt(data, key3);
        byte[] step2 = encrypt(step1, key2);
        return decrypt(step2, key1);
    }

    // 加密单个8字节块
    private byte[] encryptBlock(byte[] block, byte[] key) {
        // 生成子密钥
        byte[][] subkeys = generateSubkeys(key);

        // 执行初始置换
        byte[] permuted = permute(block, IP);

        // 分成左右两部分
        byte[] left = new byte[4];
        byte[] right = new byte[4];
        System.arraycopy(permuted, 0, left, 0, 4);
        System.arraycopy(permuted, 4, right, 0, 4);

        // 16轮Feistel网络
        for (int i = 0; i < 16; i++) {
            byte[] temp = left;
            left = right;
            right = xor(temp, fFunction(right, subkeys[i]));
        }

        // 合并左右部分
        byte[] combined = new byte[8];
        System.arraycopy(right, 0, combined, 0, 4);
        System.arraycopy(left, 0, combined, 4, 4);

        // 执行最终置换
        return permute(combined, FP);
    }

    // 解密单个8字节块
    private byte[] decryptBlock(byte[] block, byte[] key) {
        // 生成子密钥
        byte[][] subkeys = generateSubkeys(key);

        // 执行初始置换
        byte[] permuted = permute(block, IP);

        // 分成左右两部分
        byte[] left = new byte[4];
        byte[] right = new byte[4];
        System.arraycopy(permuted, 0, left, 0, 4);
        System.arraycopy(permuted, 4, right, 0, 4);

        // 16轮Feistel网络（使用逆序子密钥）
        for (int i = 15; i >= 0; i--) {
            byte[] temp = left;
            left = right;
            right = xor(temp, fFunction(right, subkeys[i]));
        }

        // 合并左右部分
        byte[] combined = new byte[8];
        System.arraycopy(right, 0, combined, 0, 4);
        System.arraycopy(left, 0, combined, 4, 4);

        // 执行最终置换
        return permute(combined, FP);
    }

    // 生成16个子密钥
    private byte[][] generateSubkeys(byte[] key) {
        byte[][] subkeys = new byte[16][6];

        // 执行PC-1置换
        byte[] pc1Key = permute(key, PC1);

        // 分成左右两部分
        byte[] left = new byte[4];
        byte[] right = new byte[4];
        System.arraycopy(pc1Key, 0, left, 0, 4);
        // 注意：PC1输出是56位，所以需要特殊处理
        System.arraycopy(pc1Key, 3, right, 0, 4);

        for (int i = 0; i < 16; i++) {
            // 左移
            left = leftShift(left, SHIFTS[i]);
            right = leftShift(right, SHIFTS[i]);

            // 合并并执行PC-2置换
            byte[] combined = new byte[7];
            System.arraycopy(left, 0, combined, 0, 4);
            // 特殊处理合并
            System.arraycopy(right, 0, combined, 3, 4);
            subkeys[i] = permute(combined, PC2);
        }

        return subkeys;
    }

    // F函数
    private byte[] fFunction(byte[] right, byte[] subkey) {
        // 扩展置换（简化版）
        byte[] expanded = expand(right);

        // 与子密钥异或
        byte[] xored = xor(expanded, subkey);

        // S盒替换（简化版）
        byte[] substituted = sBoxSubstitution(xored);

        // P置换（简化版）
        return pPermutation(substituted);
    }

    // 扩展函数（简化版）
    private byte[] expand(byte[] data) {
        byte[] expanded = new byte[6];
        // 简化的扩展逻辑
        System.arraycopy(data, 0, expanded, 0, 4);
        expanded[4] = data[0];
        expanded[5] = data[1];
        return expanded;
    }

    // S盒替换（简化版）
    private byte[] sBoxSubstitution(byte[] data) {
        // 简化的S盒逻辑
        byte[] result = new byte[4];
        for (int i = 0; i < 4; i++) {
            result[i] = (byte) ((data[i] + data[i + 2]) & 0xFF);
        }
        return result;
    }

    // P置换（简化版）
    private byte[] pPermutation(byte[] data) {
        // 简化的P置换
        byte[] result = new byte[4];
        for (int i = 0; i < 4; i++) {
            result[i] = data[3 - i];
        }
        return result;
    }

    // 通用置换函数
    private byte[] permute(byte[] input, int[] table) {
        int outputLength = (table.length + 7) / 8;
        byte[] output = new byte[outputLength];

        for (int i = 0; i < table.length; i++) {
            int bitPos = table[i] - 1;
            int bytePos = bitPos / 8;
            int bitInByte = 7 - (bitPos % 8);

            int value = (input[bytePos] >> bitInByte) & 1;

            int outputBytePos = i / 8;
            int outputBitInByte = 7 - (i % 8);
            output[outputBytePos] |= (value << outputBitInByte);
        }

        return output;
    }

    // 字节数组异或操作
    private byte[] xor(byte[] a, byte[] b) {
        byte[] result = new byte[Math.min(a.length, b.length)];
        for (int i = 0; i < result.length; i++) {
            result[i] = (byte) (a[i] ^ b[i]);
        }
        return result;
    }

    // 左移操作
    private byte[] leftShift(byte[] data, int shifts) {
        byte[] result = new byte[data.length];
        System.arraycopy(data, 0, result, 0, data.length);

        for (int s = 0; s < shifts; s++) {
            int carry = 0;
            for (int i = 0; i < data.length; i++) {
                int newCarry = (result[i] & 0x80) != 0 ? 1 : 0;
                result[i] = (byte) ((result[i] << 1) | carry);
                carry = newCarry;
            }
            if (carry != 0) {
                result[0] |= 1;
            }
        }

        return result;
    }

    // 字节数组转十六进制字符串
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b & 0xFF));
        }
        return sb.toString();
    }

    // 十六进制字符串转字节数组
    private byte[] hexToBytes(String hex) {
        // 移除可能存在的空格
        hex = hex.replaceAll("\\s", "");

        int len = hex.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("十六进制字符串长度必须是偶数");
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new DESTool();

            // 控制台测试
            System.out.println("=== DES测试 ===");
            DESTool des = new DESTool();
            String plaintext = "this is a test";
            String desKey = "12345678";

            String desCipher = des.encryptString(plaintext, desKey);
            String desDecrypted = des.decryptString(desCipher, desKey);
            System.out.println("明文: " + plaintext);
            System.out.println("密文: " + desCipher);
            System.out.println("解密后: " + desDecrypted);
            System.out.println("验证: " + plaintext.equals(desDecrypted));

            System.out.println("\n=== 三重DES测试 ===");
            String key1 = "key12345";
            String key2 = "key67890";
            String key3 = "keyabcde";
            String tripleCipher = des.tripleEncryptString(plaintext, key1, key2, key3);
            String tripleDecrypted = des.tripleDecryptString(tripleCipher, key1, key2, key3);
            System.out.println("明文: " + plaintext);
            System.out.println("密文: " + tripleCipher);
            System.out.println("解密后: " + tripleDecrypted);
            System.out.println("验证: " + plaintext.equals(tripleDecrypted));
        });
    }
}